﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Yoozoo.Gameplay;

namespace Yoozoo.Mars.Got.Timer
{
    public enum CountdownFormatType
    {
        None = 0,
        Standard = 1,
    }

    public class CountdownStandard
    {
        private int m_tick;
        private CountdownFormatType type;
        private string m_str;
        private int m_day;
        private int m_hour;
        private int m_minute;
        private int m_second;

        public CountdownStandard(int tick, int format)
        {
            m_tick = tick;
            type = (CountdownFormatType)format;
            InitTime();
        }

        private void InitTime()
        {
            if (type == CountdownFormatType.None)
            {
                return;
            }
            m_day = m_tick / (3600 * 24);
            m_hour = m_tick % (3600 * 24) / 3600;
            m_minute = m_tick % 3600 / 60;
            m_second = m_tick % 60;
        }

        private void MinusSecond()
        {
            if (m_second > 0)
            {
                m_second--;
                return;
            }

            if (m_minute > 0)
            {
                m_minute--;
                m_second = 59;
                return;
            }

            if (m_hour > 0)
            {
                m_hour--;
                m_minute = 59;
                m_second = 59;
                return;
            }

            if (m_day > 0)
            {
                m_day--;
                m_hour = 23;
                m_minute = 59;
                m_second = 59;
                return;
            }
        }

        public string GetTimeFormat()
        {
            if (type == CountdownFormatType.None)
            {
                return (m_tick--).ToString();
            }
            StringBuilder sb = new StringBuilder();

            if (m_day > 0)
            {
                sb.Append(m_day + "D ");
            }

            if (m_hour < 10)
            {
                sb.Append("0" + m_hour + ":");
            }
            else
            {
                sb.Append(m_hour + ":");
            }

            if (m_minute < 10)
            {
                sb.Append("0" + m_minute + ":");
            }
            else
            {
                sb.Append(m_minute + ":");
            }

            if (m_second < 10)
            {
                sb.Append("0" + m_second);
            }
            else
            {
                sb.Append(m_second);
            }
            MinusSecond();
            return sb.ToString();
        }
    }

    public class TimeTool : MonoBehaviour
    {
        public const bool USE_TIMER_POOL = false;
        private Dictionary<int, TeaTime> m_ttDic;
        private Dictionary<int, RealTimerInfo> m_rtDic;
        private List<TeaTime> m_ttFreeList;
        public List<TeaTime> TtFreeList
        {
            get
            {
                return m_ttFreeList;
            }
        }
        private int m_ttIndex;
        private static bool m_destroy;

        private static TimeTool _instance;
        public static TimeTool Instance
        {
            get
            {
                if (!m_destroy && (_instance == null || !_instance.gameObject))
                {
                    GameObject instanceHome = GameObject.Find("TimeTool");
                    if (instanceHome == null)
                    {
                        instanceHome = new GameObject("TimeTool");
                        _instance = instanceHome.AddComponent<TimeTool>();
                    }
                    else
                    {
                        _instance = instanceHome.GetComponent<TimeTool>() ?? instanceHome.AddComponent<TimeTool>();
                    }
                }
                return _instance;
            }
        }

        void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
                m_ttDic = new Dictionary<int, TeaTime>();
                m_rtDic = new Dictionary<int, RealTimerInfo>();
                m_ttFreeList = new List<TeaTime>();
                m_ttIndex = 0;
                m_destroy = false;
            }
        }

        void OnDestroy()
        {
            if (_instance == this)
            {
                _instance = null;
                m_destroy = true;
            }
        }

        public int GetTTNum() { return m_ttDic.Count; }

        // C#端延时
        public int Delay(float time, Action function, bool isDebug = false)
        {
            TeaTime t = this.tt(m_ttFreeList, "Delay:" + time);
            t.IsDebug = isDebug;
            var removeIndex = ++m_ttIndex;
            t.Add(time, delegate ()
            {
                function();
                t.Stop();
                m_ttDic.Remove(removeIndex);
                Despawn(t, true);
            });
            m_ttDic.Add(m_ttIndex, t);
            return m_ttIndex;
        }
        public int Delay(float time, Action<object> function, object obj)
        {
            TeaTime t = this.tt(m_ttFreeList, "Delay2:" + time);
            var removeIndex = ++m_ttIndex;
            t.Add(time, delegate ()
            {
                function(obj);
                t.Stop();
                m_ttDic.Remove(removeIndex);
                //m_ttFreeList.Add(t);
                //t.OnDespawn();
                Despawn(t, true);
            });
            m_ttDic.Add(m_ttIndex, t);
            return m_ttIndex;
        }

        public int CountdownByDuration(float duration, Action function)
        {
            TeaTime t = this.tt(m_ttFreeList, "CountdownByDuration:" + duration);
            t.Add(duration, delegate ()
            {
                if (function != null)
                {
                    function();
                }
            }).Repeat();
            m_ttDic.Add(++m_ttIndex, t);
            return m_ttIndex;
        }

        // 移除计时器或者延时器
        public void RemoveTimeEvent(int index)
        {
            TeaTime t;
            m_ttDic.TryGetValue(index, out t);
            if (t != null)
            {
                t.Stop();
                m_ttDic.Remove(index);
                Despawn(t, true);
            }
        }

        public void RemoveTimeEventRef(ref int index)
        {
            if(index > 0){
                RemoveTimeEvent(index);
                index = 0;
            }
        }
        
        //public int Countdown(long tick, Action function, Action done = null)
        //{
        //    if (function != null)
        //    {
        //        function();
        //    }
        //    TeaTime t = this.tt();
        //    t.Add(1, delegate ()
        //    {
        //        tick--;
        //        if (tick > 0)
        //        {
        //            if (function != null)
        //            {
        //                function();
        //            }
        //        }
        //        else
        //        {
        //            if (function != null)
        //            {
        //                function();
        //            }
        //            if (done != null)
        //            {
        //                done();
        //            }
        //            t.Stop();
        //        }
        //    }).Repeat();
        //    m_ttDic.Add(++m_ttIndex, t);
        //    return m_ttIndex;
        //}

        //public int Countdown(long tick, Action<long> function, Action<int> done = null)
        //{
        //    if (function != null)
        //    {
        //        function(tick);
        //    }
        //    int m_var = ++m_ttIndex;
        //    TeaTime t = this.tt();
        //    t.Add(1, delegate ()
        //    {
        //        tick--;
        //        if (tick > 0)
        //        {
        //            if (function != null)
        //            {
        //                function(tick);
        //            }
        //        }
        //        else
        //        {
        //            if (function != null)
        //            {
        //                function(tick);
        //            }
        //            if (done != null)
        //            {
        //                done(m_var);
        //            }
        //            t.Stop();
        //        }
        //    }).Repeat();
        //    m_ttDic.Add(m_ttIndex, t);
        //    return m_ttIndex;
        //}

        public int Countdown(long tick, Action function, Action done = null)
        {
            if (function != null)
            {
                function();
            }
            int m_var = ++m_ttIndex;
            TeaTime t = this.tt(m_ttFreeList, "Countdown:" + tick);
            t.SetRealTimerInfo(tick);
            //RealTimerInfo rt = new RealTimerInfo(tick);
            t.Add(1, delegate ()
            {
                long deltaTime = t.StartTime + t.Tick - TimeUtils.GetServerTimeMs();
                if (deltaTime > 0)
                {
                    if (function != null)
                    {
                        function();
                    }
                }
                else
                {
                    if (function != null)
                    {
                        function();
                    }
                    if (done != null)
                    {
                        done();
                    }
                    t.Stop();
                    m_ttDic.Remove(m_var);
                    Despawn(t, true);
                }
            }).Repeat();
            m_ttDic.Add(m_ttIndex, t);
            //m_rtDic.Add(m_ttIndex, rt);
            return m_ttIndex;
        }

        public int Countdown(long tick, Action<long> function, Action<int> done = null)
        {
            if (function != null)
            {
                function(tick);
            }
            int m_var = ++m_ttIndex;
            TeaTime t = this.tt(m_ttFreeList, "Countdown2:" + tick);
            t.SetRealTimerInfo(tick);
            //RealTimerInfo rt = new RealTimerInfo(tick);
            t.Add(1, delegate ()
            {
                long deltaTime = t.StartTime + t.Tick - TimeUtils.GetServerTimeMs();
                if (deltaTime > 0)
                {
                    if (function != null)
                    {
                        function(deltaTime);
                    }
                }
                else
                {
                    if (function != null)
                    {
                        function(deltaTime);
                    }
                    if (done != null)
                    {
                        done(m_var);
                    }
                    t.Stop();
                    m_ttDic.Remove(m_var);
                    Despawn(t, true);
                }
            }).Repeat();
            m_ttDic.Add(m_ttIndex, t);
            //m_rtDic.Add(m_ttIndex, rt);
            return m_ttIndex;
        }

        public void PrintDebugLog()
        {
            var e = m_ttDic.GetEnumerator();
            while(e.MoveNext())
            {
                e.Current.Value.PrintDebugLog();
            }
        }

        public void Despawn(TeaTime tt, bool isTtDict = false)
        {
            if (!USE_TIMER_POOL)
            {
                return;
            }
#pragma warning disable 162
            tt.OnDespawn();
            m_ttFreeList.Add(tt);
            if (isTtDict)
            {
                //Debug.Log("[TeaTime] Despawn");
            }
#pragma warning restore 162
        } 
    }

    public class RealTimerInfo
    {
        /// <summary>
        /// 计时器开始的服务器时间
        /// </summary>
        public long StartTime; 

        /// <summary>
        /// 计时器耗时
        /// </summary>
        public long Tick;

        public RealTimerInfo(long tick)
        {
            StartTime = TimeUtils.GetServerTimeMs();
            Tick = tick;
        }
    }
}
